//=============================================================================
/**
 * @file	gym_insect.c
 * @brief	虫ジムギミック
 * @author	Nozomu Saito
 *
 * モジュール名：GYM_
 */
//=============================================================================

#include "common.h"
#include "fieldsys.h"
#include "fieldmap_work.h"
#include "system/snd_tool.h"
#include "include/savedata/gimmickwork.h"
#include "../fielddata/build_model/build_model_id.h"

#include "field_gimmick_def.h"
#include "sysflag_def.h"

#include "gym_def.h"

#include "gym_local.h"
#include "gym_init.h"

#include "gym.h"
#include "pair_poke.h"

#define LIFT_NUM	(4)			//リフトの数
#define LIFT_POS_NUM	(12)	//リフトの停止場所数
#define LIFT_SPEED	(2*FX32_ONE)			//リフトの進むスピード
#define LIFT_DISP_OFS	(8*FX32_ONE)		//リフト表示オフセット

#define LIFT_ANIME_ENTRY_ID	(1)

#define CAM_SHAKE_WAIT	(1)
#define CAM_SHAKE_COUNT	(4)	//必ず偶数で
#define CAM_SHAKE_OFS	(1)
#define MOVE_WAIT	(8)		//振動停止してから、動き出すまでのウェイト
#define START_MOVE_WAIT	(4)		//リフト起動までのウェイト
typedef enum{
	CHECK_YET,			//まだ到達していない
	CHECK_ARRIVE,		//到達
	CHECK_OVER,			//過ぎた
}CHECK_RC;

typedef struct {
	int seq;							///<シーケンス保持ワーク
	FIELDSYS_WORK *fsys;
}EVENT_GYM_WORK;

typedef struct CHECK_PARAM_tag
{
	BOOL XPlus;
	BOOL ZPlus;
}CHECK_PARAM;

typedef struct LIFT_POS_tag
{
	u16 GridX;
	u16 GridZ;
}LIFT_POS;

typedef struct INSECT_GYM_TEMP_WORK_tag
{
	FIELDSYS_WORK *fsys;
	int Lift[LIFT_NUM];
	u8 ConectCount;
	u8 RailState;		//レールの状況	0:2本ある 1:赤レールのみ 2:青レールのみ 3:レールなし
	u8 NextReq;
	u8 LiftIdx;

	u8 LiftPos;
	u8 Revers;
	u8 ConectIdx;
	s8 PlayerGridOfs;		//リフトからのZグリッドオフセット

	BOOL TiltMove;			//斜め移動

	CHECK_PARAM CheckParam;

	const LIFT_POS *Next;
	VecFx32 NowVecPos;
	VecFx32 MoveVec;

	int ShakeCount;
	int ShakeWait;
	fx32 CamOfs;
	int MoveWait;
}INSECT_GYM_TEMP_WORK;

typedef struct CONECT_DATA_tag
{
	u16 ConectNum;
	u16 DstPos;
	const LIFT_POS * const Tbl;
}CONECT_DATA;

typedef struct LIFT_MOVE_INFO_tag
{
	//idx = 0:レール2本ともある 1:1番レールだけある 2:2番レールだけある 3:レールない
	const CONECT_DATA *ConectData[LIFT_POS_NUM];
}LIFT_MOVE_INFO;

//レール接続部データ
static const LIFT_POS ConectData1[] = {
	{3,31},{3,29},{9,29},{9,27},{15,28},{15,25},{9,25},{9,24},
};
static const LIFT_POS ConectData2[] = {
	{9,31},{9,29},{3,29},{3,27},{9,26},{9,25},{15,25},{15,24},
};
static const LIFT_POS ConectData3[] = {
	{15,31},{15,28},{9,27},{9,26},{3,27},{3,24},
};
static const LIFT_POS ConectData4_1[] = {
	{3,16},{3,12},{9,13},{9,10},{3,10},{3,9},
};

static const LIFT_POS ConectData4_2[] = {
	{3,16},{3,12},{9,13},{9,9}
};

static const LIFT_POS ConectData5_1[] = {
	{9,16},{9,14},{15,14},{15,11},{9,12},{9,10},{3,10},{3,9},
};

static const LIFT_POS ConectData5_2[] = {
	{9,16},{9,14},{15,14},{15,9},
};
static const LIFT_POS ConectData5_3[] = {
	{9,16},{9,14},{15,14},{15,11},{9,12},{9,9},
};

//リフト停止位置
static const LIFT_POS LiftPosition[LIFT_POS_NUM] = {
	{3,31},{9,31},{15,31},
	{3,24},{9,24},{15,24},
	{3,16},{9,16},{15,16},
	{3, 9},{9, 9},{15, 9},
};

static const CONECT_DATA Pos1Data[4] = {			//pos1
	{8,4,ConectData1}, {8,4,ConectData1}, {8,4,ConectData1}, {8,4,ConectData1}
};
static const CONECT_DATA Pos2Data[4] = {			//pos2
	{8,5,ConectData2}, {8,5,ConectData2}, {8,5,ConectData2}, {8,5,ConectData2}
};
static const CONECT_DATA Pos3Data[4] = {			//pos3
	{6,3,ConectData3}, {6,3,ConectData3}, {6,3,ConectData3}, {6,3,ConectData3}
};
static const CONECT_DATA Pos4Data[4] = {			//pos4
	{6,2,ConectData3}, {6,2,ConectData3}, {6,2,ConectData3}, {6,2,ConectData3}
};
static const CONECT_DATA Pos5Data[4] = {			//pos5
	{8,0,ConectData1}, {8,0,ConectData1}, {8,0,ConectData1}, {8,0,ConectData1}
};
static const CONECT_DATA Pos6Data[4] = {			//pos6
	{8,1,ConectData2}, {8,1,ConectData2}, {8,1,ConectData2}, {8,1,ConectData2}
};
static const CONECT_DATA Pos7Data[4] = {			//pos7
	{0,0,NULL}, {6,9,ConectData4_1}, {0,0,NULL},{4,10,ConectData4_2}
};
static const CONECT_DATA Pos8Data[4] = {			//pos8
	{8,9,ConectData5_1}, {4,11,ConectData5_2}, {6,10,ConectData5_3}, {4,11,ConectData5_2}
};
static const CONECT_DATA Pos9Data[4] = {			//pos9
	{0,0,NULL}, {0,0,NULL}, {0,0,NULL}, {0,0,NULL}
};
static const CONECT_DATA Pos10Data[4] = {			//pos10
	{8,7,ConectData5_1}, {6,6,ConectData4_1}, {0,0,NULL}, {0,0,NULL}
};
static const CONECT_DATA Pos11Data[4] = {			//pos11
	{0,0,NULL}, {0,0,NULL}, {6,7,ConectData5_3}, {4,6,ConectData4_2}
};
static const CONECT_DATA Pos12Data[4] = {			//pos12
	{0,0,NULL}, {4,7,ConectData5_2}, {0,0,NULL}, {4,7,ConectData5_2}
};

//リフトのたどるレール情報
static const LIFT_MOVE_INFO LiftMoveInfo = {
	Pos1Data,
	Pos2Data,
	Pos3Data,
	Pos4Data,
	Pos5Data,
	Pos6Data,
	Pos7Data,
	Pos8Data,
	Pos9Data,
	Pos10Data,
	Pos11Data,
	Pos12Data,
};

static BOOL GMEVENT_MoveLift(GMEVENT_CONTROL * event);
static VecFx32 GetMoveVal(const LIFT_POS *inNowPos, const LIFT_POS *inNextPos);
static void GetCheckParam(const VecFx32 *inVec, CHECK_PARAM *outParam);
static CHECK_RC CheckMove(	const BOOL inPlus,
							const fx32 inVal, const fx32 inMove,
							const u16 inGrid);
static void ShiftTcb( TCB_PTR tcb, void *work );

static BOOL GMEVENT_LeverSeWait(GMEVENT_CONTROL * event);

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:セットアップ
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetupInsectGym(FIELDSYS_WORK *fsys)
{
	int i;
	u8 lift;
	GIMMICKWORK *work;
	INSECT_GYM_WORK *insect_gym_work;
	INSECT_GYM_TEMP_WORK *insect_temp;
	F_OBJ_DATA	*data;

	//ここでギミックワークの中身を見る
	work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
	insect_gym_work = (INSECT_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_INSECT_GYM);

	//虫ジム専用ワークをアロケートして、フィールドマップ汎用ワークポインタにあてる
	fsys->fldmap->Work = sys_AllocMemory(HEAPID_FIELD, sizeof(INSECT_GYM_TEMP_WORK));
	//初期化
	MI_CpuClear8(fsys->fldmap->Work, sizeof(INSECT_GYM_TEMP_WORK));
	insect_temp = fsys->fldmap->Work;

	for(i=0;i<LIFT_NUM;i++){
		VecFx32 vec = {0,0,0};
		//リフトの位置を取得
		lift = insect_gym_work->Lift[i];
		//リフトの作成
		vec.x = LiftPosition[lift].GridX * ONE_GRID_SIZE*FX32_ONE;
		vec.x += LIFT_DISP_OFS;
		vec.z = LiftPosition[lift].GridZ * ONE_GRID_SIZE*FX32_ONE;
		insect_temp->Lift[i] = M3DO_SetMap3DObjExp(fsys->Map3DObjExp,
								BMID_ROOM_GYM02LIFT,
								&vec, NULL,
								fsys->field_3d_anime );//<リフト
	}

	//レーンの状況からレバーのアニメを変更
	switch(insect_gym_work->RailState){
	case 0:		//2本とも有効
		//ロープ
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_1);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_2);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		//レバー
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH_R);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		break;
	case 1:		//赤有効
		//ロープ
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_1);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_2);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		//レバー
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH_R);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		break;
	case 2:		//青有効
		//ロープ
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_1);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_2);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		//レバー
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH_R);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 0, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//有効
		break;
	case 3:		//2本無効
		//ロープ
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_1);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_2);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		//レバー
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH_R);	//赤
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		data = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH);	//青
		F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 1, TRUE,
							&data->RenderObj,
							fsys->field_3d_anime );	//無効
		break;
	default:
		GF_ASSERT(0)
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:レバー操作
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	inLeverNo	レバーナンバー
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_MoveInsectGymLever(FIELDSYS_WORK *fsys, const u8 inLeverNo)
{
	GIMMICKWORK *work;
	INSECT_GYM_WORK *insect_gym_work;
	F_OBJ_DATA	*data_rope;
	F_OBJ_DATA	*data_lever;
	u8 bit;
	work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
	insect_gym_work = (INSECT_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_INSECT_GYM);

	Snd_SePlay( SEQ_SE_DP_KI_GASYAN );

	if (inLeverNo == 0){
		bit = insect_gym_work->RailState & 0x01;
		//1ビットめ操作
		insect_gym_work->RailState ^= 1;
		data_rope = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_2);	//青
		data_lever = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH);	//青
		//アニメパージ
		F3DA_RemoveFld3DAnime(	fsys->field_3d_anime,
								&data_rope->RenderObj,
								BMID_ROOM_GYM02ROPE_2,
								bit);
		F3DA_RemoveFld3DAnime(	fsys->field_3d_anime,
								&data_lever->RenderObj,
								BMID_ROOM_GYM02SWITCH,
								bit);
		bit = insect_gym_work->RailState & 0x01;
		if (bit){
			//無効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 1, TRUE,
								&data_rope->RenderObj,
								fsys->field_3d_anime );	//無効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 1, TRUE,
								&data_lever->RenderObj,
								fsys->field_3d_anime );	//無効
		}else{
			//有効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_2, 0, TRUE,
								&data_rope->RenderObj,
								fsys->field_3d_anime );	//有効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH, 0, TRUE,
								&data_lever->RenderObj,
								fsys->field_3d_anime );	//有効
		}
	}else if(inLeverNo == 1){
		bit = (insect_gym_work->RailState>>1) & 0x01;
		//2ビットめ操作
		insect_gym_work->RailState ^= 2;
		data_rope = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02ROPE_1);	//赤
		data_lever = F_RES_OBJ_GetRenderObjPtr(fsys->FldResObjMng, BMID_ROOM_GYM02SWITCH_R);	//赤
		//アニメパージ
		F3DA_RemoveFld3DAnime(	fsys->field_3d_anime,
								&data_rope->RenderObj,
								BMID_ROOM_GYM02ROPE_1,
								bit);
		F3DA_RemoveFld3DAnime(	fsys->field_3d_anime,
								&data_lever->RenderObj,
								BMID_ROOM_GYM02SWITCH_R,
								bit);
		bit = (insect_gym_work->RailState>>1) & 0x01;
		if (bit){
			//無効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 1, TRUE,
								&data_rope->RenderObj,
								fsys->field_3d_anime );	//無効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 1, TRUE,
								&data_lever->RenderObj,
								fsys->field_3d_anime );	//無効
		}else{
			//有効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02ROPE_1, 0, TRUE,
								&data_rope->RenderObj,
								fsys->field_3d_anime );	//有効
			F3DA_SetFld3DAnime(	BMID_ROOM_GYM02SWITCH_R, 0, TRUE,
								&data_lever->RenderObj,
								fsys->field_3d_anime );	//有効
		}
	}else{
		GF_ASSERT(0);
	}

	OS_Printf("RailState=%d\n",insect_gym_work->RailState);

	//SE終了待ちイベントコール
	FieldEvent_Call(fsys->event, GMEVENT_LeverSeWait, NULL);
}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:リフト移動
 *
 * @param	fsys		フィールドシステムポインタ
 * @param	inLiftPos	リフト位置（0〜11）
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_MoveInsectGymLift(FIELDSYS_WORK *fsys, const u8 inLiftPos)
{
	EVENT_GYM_WORK * egw;
	INSECT_GYM_TEMP_WORK *insect_temp;
	insect_temp = (INSECT_GYM_TEMP_WORK *)fsys->fldmap->Work;

	//イベントコール
	egw = sys_AllocMemoryLo(HEAPID_WORLD, sizeof(EVENT_GYM_WORK));
	egw->seq = 0;
	egw->fsys = fsys;

	//セットアップ
	insect_temp->LiftPos = inLiftPos;
	insect_temp->NowVecPos.y = 0;
	insect_temp->ConectCount = 0;
	insect_temp->NextReq = 1;
	insect_temp->TiltMove = FALSE;

	{
		int i;
		GIMMICKWORK *work;
		INSECT_GYM_WORK *insect_gym_work;
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		insect_gym_work = (INSECT_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_INSECT_GYM);
		insect_temp->RailState = insect_gym_work->RailState;

		OS_Printf("LiftPos = %d,%d,%d,%d\n",insect_gym_work->Lift[0],insect_gym_work->Lift[1],
				insect_gym_work->Lift[2],insect_gym_work->Lift[3]);

		//4つあるリフトのどれに乗ったかを検索する
		for(i=0;i<LIFT_NUM;i++){
			if ( insect_gym_work->Lift[i] == inLiftPos ){
				insect_temp->LiftIdx = i;
				break;
			}
		}
		if (i==LIFT_NUM){
			GF_ASSERT(0);
			return ;
		}
	}



	switch(inLiftPos){
	case 3:
	case 4:
	case 5:
	case 9:
	case 10:
	case 11:
		//コネクト情報を逆再生
		insect_temp->Revers = 1;
		insect_temp->ConectIdx = LiftMoveInfo.ConectData[inLiftPos][insect_temp->RailState].ConectNum-1;
		insect_temp->PlayerGridOfs = 1;
		break;
	default:
		//コネクト情報を通常再生
		insect_temp->Revers = 0;
		insect_temp->ConectIdx = 0;
		insect_temp->PlayerGridOfs = 0;
	}

	{
		const LIFT_POS *now;
		now = &LiftMoveInfo.ConectData[inLiftPos][insect_temp->RailState].Tbl[insect_temp->ConectIdx];
		insect_temp->NowVecPos.x = now->GridX * FX32_ONE * ONE_GRID_SIZE;
		insect_temp->NowVecPos.z = now->GridZ * FX32_ONE * ONE_GRID_SIZE;
	}


	FieldEvent_Call(fsys->event, GMEVENT_MoveLift, egw);
}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:リフト移動
 *
 * @param	event	イベントポインタ
 *
 * @return	BOOL TRUE:イベント終了	FALSE:イベント継続
 */
//---------------------------------------------------------------------------
static BOOL GMEVENT_MoveLift(GMEVENT_CONTROL * event)
{
	M3DO_PTR ptr;
	FIELDSYS_WORK * fsys = FieldEvent_GetFieldSysWork(event);
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);
	INSECT_GYM_TEMP_WORK *insect_temp;
	insect_temp = (INSECT_GYM_TEMP_WORK *)fsys->fldmap->Work;

	switch (egw->seq) {
	case 0:			//連れ歩きポケモンアニメ待ち
		FieldEvent_Call(fsys->event, PairPokeEvAnm_WaitAnmEvent, NULL);
		(egw->seq) ++;
		break;
	case 1:
		//TCB作成（フィールドOBJより速く処理されるようにプライオリティを決定する）
		TCB_Add(ShiftTcb, egw, 0);
		(egw->seq) ++;
		break;
	case 10:
		//解放
		sys_FreeMemoryEz(egw);
		return TRUE;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	リフト移動ベクトル取得
 *
 *	@param	*inNowPos		現在位置
 *	@param	*inNextPos		目的位置
 *
 *	@return vec		移動ベクトル
 */
//-----------------------------------------------------------------------------
static VecFx32 GetMoveVal(const LIFT_POS *inNowPos, const LIFT_POS *inNextPos)
{
	VecFx32 vec;
	//目的のポイントから、現在のポイントを引く
	vec.x = (inNextPos->GridX - inNowPos->GridX) * FX32_ONE;
	vec.z = (inNextPos->GridZ - inNowPos->GridZ) * FX32_ONE;
	vec.y = 0;
	OS_Printf("MoveVec= %x,%x\n",vec.x, vec.z);
	return vec;
}

//----------------------------------------------------------------------------
/**
 *	@brief	座標到達チェックのためのパラメータ取得
 *
 *	@param	*inVec		方向ベクトル
 *	@param	*outParam	パラメータ格納バッファ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void GetCheckParam(const VecFx32 *inVec, CHECK_PARAM *outParam)
{
	//Xの変化が・・・
	if (inVec->x >= 0){
		//＋のときは、到達チェックで、「以上」を見る
		outParam->XPlus = TRUE;
	}else{
		//−のときは、到達チェックで、「以下」を見る
		outParam->XPlus = FALSE;
	}
	//Zの変化が・・・
	if (inVec->z >= 0){
		//＋のときは、到達チェックで、「以上」を見る
		outParam->ZPlus = TRUE;
	}else{
		//−のときは、到達チェックで、「以下」を見る
		outParam->ZPlus = FALSE;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief		移動チェック
 *
 *	@param		inPlus		判定に使う正負
 *	@param		inVal		基点値
 *	@param		inMove		変化量
 *	@param		inGrid		目的地のグリッド座標
 *
 *	@return		rc		CHECK_RC参照
 */
//-----------------------------------------------------------------------------
static CHECK_RC CheckMove(	const BOOL inPlus,
							const fx32 inVal, const fx32 inMove,
							const u16 inGrid)
{
	CHECK_RC rc;
	fx32 val;
	val = inGrid * ONE_GRID_SIZE * FX32_ONE;

	rc = CHECK_YET;

	if ( inVal + inMove == val ){
		rc = CHECK_ARRIVE;
	}else{
		if ( inPlus ){
			if (inVal + inMove > val){
				rc = CHECK_OVER;
			}
		}else{
			OS_Printf("%x+%x=%x\n",inVal,inMove,inVal + inMove);
			if (inVal + inMove < val){
				rc = CHECK_OVER;
			}
		}
	}

	return rc;

}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:終了処理
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_EndInsectGym(FIELDSYS_WORK *fsys)
{
	INSECT_GYM_TEMP_WORK *insect_temp;
	insect_temp = (INSECT_GYM_TEMP_WORK *)fsys->fldmap->Work;
	sys_FreeMemoryEz(insect_temp);
	fsys->fldmap->Work = NULL;
}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:TCB
 *
 * @param	tcb		TCBポインタ
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void ShiftTcb( TCB_PTR tcb, void *work )
{
	EVENT_GYM_WORK * egw = work;
	FIELDSYS_WORK * fsys = egw->fsys;
	INSECT_GYM_TEMP_WORK *insect_temp = (INSECT_GYM_TEMP_WORK *)fsys->fldmap->Work;
	switch (egw->seq) {
	case 2:
		{
			FIELD_OBJ_PTR fldobj;
			FIELD_OBJ_PTR fldobj_pair;
			if ( PairPoke_IsPairPoke(fsys) ){
				fldobj = Player_FieldOBJGet( fsys->player );
				fldobj_pair = PairPoke_GetFldObjPtr(fsys);
				//アニメ発行
				if (insect_temp->Revers){
					FieldOBJ_AcmdSet(fldobj,AC_WALK_D_8F);	//自機下移動
					FieldOBJ_AcmdSet(fldobj_pair,AC_WALK_D_8F);	//連れ歩き下移動
				}else{
					FieldOBJ_AcmdSet(fldobj,AC_WALK_U_8F);	//自機上移動
					FieldOBJ_AcmdSet(fldobj_pair,AC_WALK_U_8F);	//連れ歩き上移動
				}
			}else{
				fldobj = Player_FieldOBJGet( fsys->player );
				//アニメ発行
				if (insect_temp->Revers){
					FieldOBJ_AcmdSet(fldobj,AC_WALK_D_8F);	//自機下移動
				}else{
					FieldOBJ_AcmdSet(fldobj,AC_WALK_U_8F);	//自機上移動
				}
			}
			(egw->seq) ++;
		}
	case 3:
		{
			FIELD_OBJ_PTR fldobj;
			fldobj = Player_FieldOBJGet( fsys->player );

			if ( PairPoke_IsPairPoke(fsys) ){
				FIELD_OBJ_PTR fldobj_pair;
				fldobj_pair = PairPoke_GetFldObjPtr(fsys);
				//アニメ待ち
				if( FieldOBJ_AcmdSetCheck(fldobj)&&FieldOBJ_AcmdSetCheck(fldobj_pair) ){ //アニメセットできるか?
					FieldOBJ_AcmdSet(fldobj,AC_ANM_PAUSE_ON); //出来る。動きをポーズ
					insect_temp->MoveWait = 0;
					(egw->seq)	++;
				}
			}else{
				//アニメ待ち
				if( FieldOBJ_AcmdSetCheck(fldobj) ){ //アニメセットできるか?
					FieldOBJ_AcmdSet(fldobj,AC_ANM_PAUSE_ON); //出来る。動きをポーズ
					insect_temp->MoveWait = 0;
					(egw->seq)	++;
				}
			}
		}
		break;
	case 4:
		if (insect_temp->MoveWait++>= START_MOVE_WAIT){
			//リフトのアニメセット
			M3DO_PTR obj_ptr;
			NNSG3dResTex *tex;
			obj_ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, insect_temp->LiftIdx);
			tex = GetMapResourceBmTexturePTR(fsys->MapResource);
			F3DASub_SetUpAnimation(	fsys->field_3d_anime,
									fsys->AnimeContMng,
									LIFT_ANIME_ENTRY_ID,
									BMID_ROOM_GYM02LIFT,
									M3DO_GetRenderObj(obj_ptr),
									M3DO_GetObjModel(obj_ptr),
									tex,1,
									LOOP_INFINIT,
									FALSE);
			F3DASub_StartAnimation(fsys->AnimeContMng, LIFT_ANIME_ENTRY_ID, 0);
			Snd_SePlay( SEQ_SE_GS_ITOMARU_ROBO );
			(egw->seq)	++;
		}
		break;
	case 5:			//リフト移動
		{
			u16 lift_pos;
			int conect_num;
			int rail_state;
			const LIFT_POS *now;
			CHECK_RC x_rc, z_rc;

			lift_pos = insect_temp->LiftPos;
			rail_state = insect_temp->RailState;

			if (insect_temp->NextReq){
				fx32 dot;		//内積を格納
				//変更値の取得
				if ( insect_temp->Revers ){
					now = &LiftMoveInfo.ConectData[lift_pos][rail_state].Tbl[insect_temp->ConectIdx];
					insect_temp->Next = &LiftMoveInfo.ConectData[lift_pos][rail_state].Tbl[insect_temp->ConectIdx-1];
					OS_Printf("now_next=(%d,%d)_(%d,%d)\n",now->GridX, now->GridZ,
							insect_temp->Next->GridX, insect_temp->Next->GridZ );
				}else{
					now = &LiftMoveInfo.ConectData[lift_pos][rail_state].Tbl[insect_temp->ConectIdx];
					insect_temp->Next = &LiftMoveInfo.ConectData[lift_pos][rail_state].Tbl[insect_temp->ConectIdx+1];
					OS_Printf("now_next=(%d,%d)_(%d,%d)\n",now->GridX, now->GridZ,
							insect_temp->Next->GridX, insect_temp->Next->GridZ );
				}
				insect_temp->MoveVec = GetMoveVal(now, insect_temp->Next);
				//チェックパラメータ取得
				GetCheckParam(&insect_temp->MoveVec, &insect_temp->CheckParam);
				//単位ベクトル化
				VEC_Normalize(&insect_temp->MoveVec, &insect_temp->MoveVec);
				OS_Printf("NORM=%x,%x\n",insect_temp->MoveVec.x, insect_temp->MoveVec.z);

				//方向ベクトルとX方向ベクトルとの内積を計算
				{
					VecFx32 vec = {FX32_ONE,0,0};
					dot = VEC_DotProduct(&insect_temp->MoveVec, &vec);
				}

				//進むスピードを設定
				{
					VecFx32 vec = {0,0,0};
					VEC_MultAdd( LIFT_SPEED, &insect_temp->MoveVec, &vec , &insect_temp->MoveVec);
				}

				//内積が0か1以外は斜め移動とみなす。
				if ( (insect_temp->TiltMove==FALSE) && ((dot!=0)&&(dot!=FX32_ONE)) ){
					//斜め移動開始。フラグ立てる
					insect_temp->TiltMove = TRUE;
					//マップロードシステムをパージ
					DivMapPurgeTarget(fsys->map_cont_dat);
				}else if (insect_temp->TiltMove == TRUE){
					//斜め移動フラグ落とす
					insect_temp->TiltMove = FALSE;
					//マップロードシステムをバインド
					DivMapBindTarget(Player_VecPosPtrGet(fsys->player), fsys->map_cont_dat);
					OS_Printf("バインドしたときの座標:%x,%x\n",
							Player_VecPosPtrGet(fsys->player)->x,Player_VecPosPtrGet(fsys->player)->z);
				}
				//更新オフ
				insect_temp->NextReq = 0;
			}
			OS_Printf("X_CHECK=%x,%x,%x\n",insect_temp->NowVecPos.x, insect_temp->MoveVec.x,
					insect_temp->Next->GridX*FX32_ONE*ONE_GRID_SIZE);
			OS_Printf("Z_CHECK=%x,%x,%x\n",insect_temp->NowVecPos.z, insect_temp->MoveVec.z,
					insect_temp->Next->GridZ*FX32_ONE*ONE_GRID_SIZE);
			x_rc = CheckMove(insect_temp->CheckParam.XPlus,
					insect_temp->NowVecPos.x, insect_temp->MoveVec.x, insect_temp->Next->GridX);
			z_rc = CheckMove(insect_temp->CheckParam.ZPlus,
					insect_temp->NowVecPos.z, insect_temp->MoveVec.z, insect_temp->Next->GridZ);

			if (x_rc == CHECK_OVER){
				insect_temp->MoveVec.x = 0;
			}
			if (z_rc == CHECK_OVER){
				insect_temp->MoveVec.z = 0;
			}


			//ベクトル加算で、目的のコネクトポイントに到達する（過ぎる）場合、値の調整+次のポイント準備
			if ( (x_rc!=CHECK_YET) && (z_rc!=CHECK_YET) ){	//到達OR通過
				//コネクトポイントにセット
				insect_temp->NowVecPos.x = insect_temp->Next->GridX * ONE_GRID_SIZE*FX32_ONE;
				insect_temp->NowVecPos.z = insect_temp->Next->GridZ * ONE_GRID_SIZE*FX32_ONE;
				//カウンタインクリメント
				insect_temp->ConectCount++;
				//すべてのコネクトを通過した？
				conect_num = LiftMoveInfo.ConectData[lift_pos][rail_state].ConectNum;
				if( insect_temp->ConectCount >= conect_num-1 ){
					GIMMICKWORK *work;
					INSECT_GYM_WORK *insect_gym_work;
					work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
					insect_gym_work = (INSECT_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_INSECT_GYM);

					//ポイントの書き換え
					insect_gym_work->Lift[ insect_temp->LiftIdx ] = LiftMoveInfo.ConectData[lift_pos][rail_state].DstPos;
					OS_Printf("リフト%d:目的ポイント%d\n",
							insect_temp->LiftIdx, LiftMoveInfo.ConectData[lift_pos][rail_state].DstPos);
					//目的地に到着したとみなす
					{
						//リフトアニメパージ
						F3DASub_RereaseAnimation(	fsys->field_3d_anime,
													fsys->AnimeContMng,
													LIFT_ANIME_ENTRY_ID	);
					}
					Snd_SeStopBySeqNo( SEQ_SE_GS_ITOMARU_ROBO, 1 );
					(egw->seq) ++;
				}else{
					//次のコネクト情報をセット
					if (insect_temp->Revers){
						insect_temp->ConectIdx--;
					}else{
						insect_temp->ConectIdx++;
					}
					insect_temp->NextReq = 1;
				}
			}else{
				//値加算
				VEC_Add(&insect_temp->NowVecPos , &insect_temp->MoveVec, &insect_temp->NowVecPos);
			}

			OS_Printf("vecXZ=%x,%x\n",insect_temp->NowVecPos.x, insect_temp->NowVecPos.z);

			{
				M3DO_PTR ptr;
				int entry;

				VecFx32 lift_vec;
				FIELD_OBJ_PTR fldobj;

				entry = insect_temp->Lift[ insect_temp->LiftIdx ];
				ptr = M3DO_GetMap3DObjData(fsys->Map3DObjExp, entry);
				lift_vec = insect_temp->NowVecPos;
				lift_vec.x += LIFT_DISP_OFS;
				//リフト座標更新
				M3DO_SetGlobalVec(ptr, &lift_vec);

				//自機の座標セット
				{
					VecFx32 player_vec;
					VecFx32 ofs_vec = {8*FX32_ONE, 0, 8*FX32_ONE};
					player_vec = insect_temp->NowVecPos;
					VEC_Add(&player_vec , &ofs_vec, &player_vec);
					player_vec.z += (insect_temp->PlayerGridOfs*(FX32_ONE*ONE_GRID_SIZE));

					fldobj = Player_FieldOBJGet( fsys->player );
					FieldOBJ_VecPosSet( fldobj, &player_vec );

					//連れ歩き
					if ( PairPoke_IsPairPoke(fsys) ){
						VecFx32 pair_vec;
						s8 pair_grid_ofs = 1 - insect_temp->PlayerGridOfs;
						pair_vec = insect_temp->NowVecPos;
						VEC_Add(&pair_vec , &ofs_vec, &pair_vec);
						pair_vec.z += (pair_grid_ofs*(FX32_ONE*ONE_GRID_SIZE));
						fldobj = PairPoke_GetFldObjPtr(fsys);
						FieldOBJ_VecPosSet( fldobj, &pair_vec );
					}
				}

			}
		}
		break;
	case 6:
		{
			FIELD_OBJ_PTR fldobj;
			fldobj = Player_FieldOBJGet( fsys->player );

			//自機座標更新
			FieldOBJ_NowPosGX_Set( fldobj, insect_temp->Next->GridX );
			FieldOBJ_NowPosGY_Set( fldobj, 0 );
			FieldOBJ_NowPosGZ_Set( fldobj, insect_temp->Next->GridZ+insect_temp->PlayerGridOfs );
			FieldOBJ_GPosUpdate( fldobj );
			FieldOBJ_AcmdSet(fldobj,AC_ANM_PAUSE_OFF);	//ポーズ解除
			if ( PairPoke_IsPairPoke(fsys) ){
				FIELD_OBJ_PTR fldobj_pair;
				fldobj_pair = PairPoke_GetFldObjPtr(fsys);
				//連れ歩き座標更新
				FieldOBJ_NowPosGX_Set( fldobj_pair, insect_temp->Next->GridX );
				FieldOBJ_NowPosGY_Set( fldobj_pair, 0 );
				FieldOBJ_NowPosGZ_Set( fldobj_pair, insect_temp->Next->GridZ+(1-insect_temp->PlayerGridOfs) );
				FieldOBJ_GPosUpdate( fldobj_pair );
			}

			//カメラゆれ準備
			insect_temp->ShakeCount = 0;
			insect_temp->ShakeWait = 0;
			if ( Player_DirGet(fsys->player) == DIR_DOWN ){			//下向き
				insect_temp->CamOfs = CAM_SHAKE_OFS * FX32_ONE;	//初回振動はしたから
			}else{													//上向き
				insect_temp->CamOfs = (-CAM_SHAKE_OFS) * FX32_ONE;	//初回振動は上から
			}
		}
		(egw->seq) ++;
		break;
	case 7:	//カメラゆれ
		{
			VecFx32 move = {0,0,0};

			move.z = insect_temp->CamOfs;

			if (insect_temp->ShakeWait++ == 0){
				GFC_ShiftCamera(&move, fsys->camera_ptr);
				insect_temp->ShakeCount++;
			}else if (insect_temp->ShakeWait > CAM_SHAKE_WAIT){
				insect_temp->ShakeWait = 0;
				insect_temp->CamOfs *= (-1);
			}

			if (insect_temp->ShakeCount >= CAM_SHAKE_COUNT){
				insect_temp->MoveWait = 0;
				(egw->seq) ++;
			}
		}
		break;
	case 8:
		{
			FIELD_OBJ_PTR fldobj;

			if (insect_temp->MoveWait++ < MOVE_WAIT){
				break;
			}
			fldobj = Player_FieldOBJGet( fsys->player );

			if ( PairPoke_IsPairPoke(fsys) ){
				FIELD_OBJ_PTR fldobj_pair;
				fldobj_pair = PairPoke_GetFldObjPtr(fsys);
				//アニメ発行
				if (insect_temp->Revers){
					FieldOBJ_AcmdSet(fldobj,AC_WALK_D_8F);	//自機下移動
					FieldOBJ_AcmdSet(fldobj_pair,AC_WALK_D_8F);	//連れ歩き下移動
				}else{
					FieldOBJ_AcmdSet(fldobj,AC_WALK_U_8F);	//自機上移動
					FieldOBJ_AcmdSet(fldobj_pair,AC_WALK_U_8F);	//連れ歩き上移動
				}
			}else{
				//アニメ発行
				if (insect_temp->Revers){
					FieldOBJ_AcmdSet(fldobj,AC_WALK_D_8F);	//自機下移動
				}else{
					FieldOBJ_AcmdSet(fldobj,AC_WALK_U_8F);	//自機上移動
				}
			}
			(egw->seq) ++;
		}
		break;
	case 9:
		{
			FIELD_OBJ_PTR fldobj;
			fldobj = Player_FieldOBJGet( fsys->player );

			if ( PairPoke_IsPairPoke(fsys) ){
				FIELD_OBJ_PTR fldobj_pair;
				fldobj_pair = PairPoke_GetFldObjPtr(fsys);
				//アニメ待ち
				if( FieldOBJ_AcmdSetCheck(fldobj)&&FieldOBJ_AcmdSetCheck(fldobj_pair) ){ //アニメセットできるか?
					//連れ歩きアニメコマンド破棄
					FieldOBJ_AcmdFree( fldobj_pair );
					//タスク削除
					TCB_Delete(tcb);
					(egw->seq) ++;
				}
			}else{
				//アニメ待ち
				if( FieldOBJ_AcmdSetCheck(fldobj)  ){ //アニメセットできるか?
					//タスク削除
					TCB_Delete(tcb);
					(egw->seq) ++;
				}
			}
		}
		break;
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	虫ジム:レバーSE待ち
 *
 * @param	event	イベントポインタ
 *
 * @return	BOOL TRUE:イベント終了	FALSE:イベント継続
 */
//---------------------------------------------------------------------------
static BOOL GMEVENT_LeverSeWait(GMEVENT_CONTROL * event)
{
	if ( Snd_SePlayCheck(SEQ_SE_DP_KI_GASYAN) == FALSE ){
		return TRUE;
	}

	return FALSE;
}